import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class ServerObject {
	
	private List<Client_itf> clActif;
	private ServerObjectState lock;
	private int id;
	private Object objet; //dernière valeur connue de l'objet
	private ReentrantLock verrou;  //assure qu'un seul client prend le verrou en écriture en m temps
	
	public ServerObject(int id, Object o){
		System.out.println("Nouvelle version");
		this.id = id;
		objet = o;
		clActif = new ArrayList<Client_itf>();
		lock = ServerObjectState.NL;
		verrou = new ReentrantLock();
	}
	
	/*
	 * lock_read
	 * met un verrou en lecture sur le server_object
	 */	
	public Object lock_read(Client_itf clDemandeur){
		System.out.println("ServerObject:" + this + "lock_read avec verrou initial : " + lock);
		
		if(!verrou.tryLock()){
			return null;
		}
		switch(lock){
		case NL: //passer en read locked
			lock = ServerObjectState.RL;
			break;
		
		case RL: //rajoute un client en lecture
			break;
		
		case WL: //demander la liberation du write lock
			try {
				if(clActif.size() > 1){
					System.out.println("[ lock_read() - ServerObject ] Les client actif en écriture n'était pas le seul");
				}
				for(Client_itf cl : clActif){
					objet = cl.reduce_lock(id);
				}
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			//passer en read_locked
			lock = ServerObjectState.RL;
			break;
		
		default:
			System.out.println("GROS PROBLEME");
		}
		
		System.out.println("SharedObject:" + this + "lock_read avec verrou : " + lock);
		clActif.add(clDemandeur);
		verrou.unlock();
		return objet;
	}
	
	/*
	 * lock_write
	 * met un verrou en écriture sur le server_object
	 */	
	 public Object lock_write(Client_itf clDemandeur){
		System.out.println("ServerObject:" + this + "lock_write avec verrou intial : " + lock);
		
		if(!verrou.tryLock()){
			return null;
		}
    	
		switch(lock){
		case NL: //passer en write locked
			lock = ServerObjectState.WL;
			break;
		
		case RL: //demander la libération du read_lock
			for(Client_itf cl : clActif){
				if(clDemandeur.equals(cl)){
					System.out.println("On a pas traité l'émetteur");
				}
				else
				{
					try {
						cl.invalidate_reader(id);
					} catch (RemoteException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			lock = ServerObjectState.WL;
			break;
		
		case WL: //demander la libération du write lock
			try {
				if(clActif.size() > 1){
					System.out.println("[ lock_write() - ServerObject ] Les clients actifs en écriture n'était pas unique");
				}
				for(Client_itf cl : clActif){
					System.out.println("Invalidate writer");
					objet = cl.invalidate_writer(id);
				}
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			//Repasser en write lock
			lock = ServerObjectState.WL;
			break;
		
		default:
			System.out.println("GROS PROBLEME");
		}
		
		System.out.println("ServerObject:" + this + " lock_write avec verrou : " + lock);
		clActif.clear();
		clActif.add(clDemandeur);
		verrou.unlock();
		return objet;
	}
}